package cn.yudao.ymcc.service.impl;

import cn.yudao.ymcc.LoginOpenFeign;
import cn.yudao.ymcc.constant.SmsCodeConstant;
import cn.yudao.ymcc.domain.*;
import cn.yudao.ymcc.dto.RedisSmsDto;
import cn.yudao.ymcc.dto.UserInfoParamDto;
import cn.yudao.ymcc.dto.UserRegisterDTO;
import cn.yudao.ymcc.feignconfig.TokenFeignInterceptor;
import cn.yudao.ymcc.mapper.UserAccountMapper;
import cn.yudao.ymcc.mapper.UserBaseInfoMapper;
import cn.yudao.ymcc.mapper.UserCodeMapper;
import cn.yudao.ymcc.mapper.UserMapper;
import cn.yudao.ymcc.result.JSONResult;
import cn.yudao.ymcc.service.IUserCodeService;
import cn.yudao.ymcc.service.IUserService;
import cn.yudao.ymcc.utils.AssertUtil;
import cn.yudao.ymcc.utils.BitStatesUtils;
import cn.yudao.ymcc.utils.SecurityGetUserInfoUtil;
import cn.yudao.ymcc.utils.StrUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author whale.jia
 * @since 2022-08-04
 */
@Service

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); // 给密码加密

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private LoginOpenFeign loginOpenFeign;

    @Autowired
    private UserBaseInfoMapper userBaseInfoMapper;

    @Autowired
    private UserAccountMapper userAccountMapper;

    @Autowired
    private UserCodeMapper userCodeMapper;


    @Autowired
    private IUserCodeService userCodeService;



    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(UserRegisterDTO userRegisterDTO) {
        // 校验手机验证码是否相同
        AssertUtil.isTrue(phoneCodeEq(userRegisterDTO), "手机验证码错误");
        // 判断用户是否已经注册
        AssertUtil.isFalse(repeatRegister(userRegisterDTO),"当前用户已经注册");
        // 根据信息填充Login表
        Login login = insertLoginDB(userRegisterDTO);
        // 根据信息填充user表
        User user = insertUserDB(login.getId(), userRegisterDTO);
        // 存入当前用户的邀请码
        insertUserCode(user.getId());
        //
        // 根据信息填充t_user_base_info表
        insertUserBaseInfoDB(user,userRegisterDTO);
        // 根据信息填充t_user_account表
        insertUserAccountDB(user,userRegisterDTO);
        // 清空redis
        redisTemplate.delete(SmsCodeConstant.SMS_PHONE + userRegisterDTO.getMobile());

    }

    /**
    * @Title: phoneCodeEq
    * @Description: 判断手机验证码是否一致
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 19:59
    * @Parameters:
    * @Return
    */
    public boolean phoneCodeEq(UserRegisterDTO userRegisterDTO){
        // 获取redis中的数据
        String key = SmsCodeConstant.SMS_PHONE + userRegisterDTO.getMobile();
        RedisSmsDto redisSmsDto = (RedisSmsDto)redisTemplate.opsForValue().get(key);
        // 判断redissmsdto是否存在
        AssertUtil.isNotNull(redisSmsDto,"手机号错误");
        // 判断手机验证码是否一致
        if (!StringUtils.equalsIgnoreCase(userRegisterDTO.getSmsCode(), redisSmsDto.getCode())) {
            return false;
        }
        return true;
    }

    /**
    * @Title: repeatRegister
    * @Description: 判断当前手机号是否已经注册
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 20:16
    * @Parameters:
    * @Return
    */
    public boolean repeatRegister(UserRegisterDTO userRegisterDTO){
        EntityWrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone", userRegisterDTO.getMobile());
        List<User> userList = userMapper.selectList(wrapper);
        if (userList != null && userList.size() > 0){
            return true;
        }
        return false;
    }

    /**
    * @Title: insertLoginDB
    * @Description: 填充数据到login表
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 20:25
    * @Parameters:
    * @Return
    */
    public Login insertLoginDB(UserRegisterDTO userRegisterDTO){
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        Login login = new Login();
        login.setUsername(userRegisterDTO.getMobile()); // 用户名用手机号赋值
        String encode = passwordEncoder.encode(userRegisterDTO.getPassword()); // 对密码进行加密
        login.setPassword(encode);
        login.setType(userRegisterDTO.getRegChannel());
        // 添加login表单数据
        JSONResult jsonResult = loginOpenFeign.saveOrUpdate(login);
        String data = (String)jsonResult.getData();
        Login login1 = JSONObject.parseObject(data, Login.class);
        return login1;
    }

    /**
    * @Title: insertUserDB
    * @Description: 填充数据到user表
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 20:36
    * @Parameters:
    * @Return
    */
    public User insertUserDB(Long loginId,UserRegisterDTO userRegisterDTO){
        User user = new User();
        user.setLoginId(loginId);
        user.setPhone(userRegisterDTO.getMobile());
        user.setCreateTime(System.currentTimeMillis());
        user.setNickName(userRegisterDTO.getMobile());
        // 判断是否有邀请人
        if (userRegisterDTO.getCode() != null){
            Wrapper wrapper = new EntityWrapper<>();
            wrapper.eq("code",userRegisterDTO.getCode());
            UserCode userCode = userCodeService.selectOne(wrapper);
            if (userCode != null)
            user.setInvitationUserId(userCode.getUserId());
        }
        Long states = BitStatesUtils.batchAddState(0L,
                BitStatesUtils.OP_REGISTED,
                BitStatesUtils.OP_ACTIVED,
                BitStatesUtils.OP_AUTHED_PHONE
        );
        user.setBitState(states);
        userMapper.insert(user);
        return user;
    }

    /**
    * @Title: insertUserCode
    * @Description: 添加验证码和对应的userid到code表
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/10 18:51
    * @Parameters:
    * @Return
    */
    public void insertUserCode(Long userId){
        List<UserCode> userCodes = userCodeService.selectList(null);

        UserCode userCode = new UserCode();
        String code = StrUtils.getRandomString(4);
        long count = userCodes.stream().filter(userCode1 -> code.equals(userCode1.getCode())).count();

        userCode.setCode(code);
        userCode.setUserId(userId);
        userCodeMapper.insert(userCode);
        Wrapper userCodeEntityWrapper = new EntityWrapper();
    }

    /**
    * @Title: insertUserBaseInfoDB
    * @Description: 新增UserBaseInfo表
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 21:04
    * @Parameters:
    * @Return
    */
    public void insertUserBaseInfoDB(User user, UserRegisterDTO userRegisterDTO){
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setCreateTime(user.getCreateTime());
        userBaseInfo.setId(user.getId());
        userBaseInfo.setRegChannel(userRegisterDTO.getRegChannel());
        Wrapper userBaseInfoEntityWrapper = new EntityWrapper();
        userBaseInfoEntityWrapper.eq("user_id",user.getId());
        UserCode userCode = userCodeService.selectOne(userBaseInfoEntityWrapper);
        userBaseInfo.setReferId(userCode.getUserId());
        userBaseInfoMapper.insert(userBaseInfo);
    }

    /**
    * @Title: insertUserAccountDB
    * @Description: 新增t_user_account表数据
    * @Author: Mr.Jia
    * @Version: 1.0
    * @Date:  2022/8/6 21:06
    * @Parameters:
    * @Return
    */
    public void insertUserAccountDB(User user, UserRegisterDTO userRegisterDTO){
        UserAccount userAccount = new UserAccount();
        userAccount.setId(user.getId());
        userAccount.setCreateTime(user.getCreateTime());
        userAccountMapper.insert(userAccount);
    }

}
